package com.yiboshi.rehrs.util;

import cn.hutool.core.thread.ThreadUtil;
import com.yiboshi.rehrs.helper.ProxyHelper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.http.HttpHost;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import static org.springframework.security.crypto.keygen.KeyGenerators.string;

@Slf4j
public class OkHttpUtil {

    // 优化连接池配置，减少空闲连接数
    private static final ConnectionPool connectionPool = new ConnectionPool(16, 5, TimeUnit.MINUTES);

    // 使用 volatile 确保多线程环境下的可见性
    private static volatile OkHttpClient defaultClient = new OkHttpClient.Builder()
            .connectionPool(connectionPool)
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .build();

    // 忽略证书验证的客户端
    private static volatile OkHttpClient insecureClient;

    // 请求配置
    private String url;
    private String method = "GET"; // 默认方法
    private String jsonBody;

    private byte[] bodyBytes;
    private int retryCount = 1; // 默认重试次数  请求次数 0-1表示一次 2表示请求2次
    private long timeoutMillis = 10_000; // 默认超时时间
    private final Map<String, String> headers = new HashMap<>();
    private Supplier<HttpHost> proxySupplier; // 动态代理提供者

    public OkHttpUtil() {

    }

    // 链式设置 URL
    public OkHttpUtil url(String url) {
        this.url = url;
        if(url.startsWith("https")){
            this.ignoreCertificates = true;
        }else{
            this.ignoreCertificates = false;
        }
        return this;
    }

    // 链式设置 GET 方法
    public OkHttpUtil get() {
        this.method = "GET";
        return this;
    }

    // 链式设置 POST 方法
    public OkHttpUtil post(String jsonBody) {
        this.method = "POST";
        this.jsonBody = jsonBody;
        this.bodyBytes = jsonBody.getBytes(StandardCharsets.UTF_8);
        return this;
    }

    public OkHttpUtil post(byte[] bodyBytes) {
        this.method = "POST";
        //this.jsonBody = jsonBody;
        this.bodyBytes = bodyBytes;
        return this;
    }

    // 链式设置重试次数
    public OkHttpUtil retryCount(int retryCount) {
        if(retryCount<=0){
            retryCount = 1; //不重试
        }
        this.retryCount = retryCount;
        return this;
    }

    // 链式设置超时时间
    public OkHttpUtil timeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
        return this;
    }

    // 链式设置单个 Header
    public OkHttpUtil addHeader(String key, String value) {
        this.headers.put(key, value);
        return this;
    }

    // 链式设置多个 Headers
    public OkHttpUtil headers(Map<String, String> headers) {
        this.headers.putAll(headers);
        return this;
    }

    // 链式设置动态代理提供者
    public OkHttpUtil proxySupplier(Supplier<HttpHost> proxySupplier) {
        this.proxySupplier = proxySupplier;
        return this;
    }

    // 链式设置忽略证书验证
    private boolean ignoreCertificates = true;

    public OkHttpUtil ignoreCertificates(boolean ignoreCertificates) {
        this.ignoreCertificates = ignoreCertificates;
        return this;
    }

    // 优化重试机制，增加重试间隔时间，并在重试时更换代理
    public String execute()  {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("URL must be set");
        }

        Request.Builder requestBuilder = new Request.Builder()
                .url(url);

        // 设置请求方法
        if ("POST".equals(method)) {
            RequestBody body = RequestBody.create(bodyBytes);
            requestBuilder.post(body);
        } else {
            requestBuilder.get();
        }

        // 添加自定义 Headers
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

        Request request = requestBuilder.build();
        Exception lastException = null;

        for (int i = 0; i < retryCount; i++) { //retryCount==1不重试
            //boolean notProxy = this.url.contains("211.156.197.65")||this.url.contains("ldxp.cn");
            //api接口不重试默认使用代理，如果有重试最后一次重试不使用代理
            boolean useProxy = (retryCount==1&&url.contains("/api/user/1000"))||(i<retryCount-1);
            OkHttpClient client = buildClient(useProxy);
            //if (i > 0) {
           Proxy proxy = client.proxy();
           String proxyStr = proxy != null ? proxy.address().toString() .substring(1): "No Proxy";
            //}
            Response response = null;
            long startTime = System.currentTimeMillis();
            try{

                response = client.newCall(request).execute();
                if (response.isSuccessful()) {

                    try {
                        String res = response.body().string();
                        long endTime = System.currentTimeMillis();
                        log.info("success okhttp：{},proxy:{},单次time:{},,url:{}，res:{}",i,proxyStr,(endTime-startTime),url,"");
                        return res; // 成功获取响应体后立即返回，不再重试
                    } catch (IOException e) {
                        long endTime = System.currentTimeMillis();
                        log.info("fail okhttp：{},proxy:{},单次time:{},,url:{}，res:{}",i,proxyStr,(endTime-startTime),url,"");
                        log.error("Error reading response body,{}", e.getMessage());
                        throw e;
                    }
                } else {
                    throw new IOException("Unexpected code " + response);
                }
            }catch (Exception e) {
                long endTime = System.currentTimeMillis();
                String message = e.getMessage();
                if((message.contains("timeout")||message.contains("timed out"))&&proxyStr.contains(":")){
                    ProxyHelper.addErrorIp(proxyStr);
                }
                log.error("fail okhttp:{},{} ,proxy:{},单次time:{},url:{}",i,message,proxyStr,(endTime-startTime),url);
                lastException = e;
                // 记录日志或处理特定异常
            }finally {
                CloseUtils.close(response);
            }
        }
        throw  new RuntimeException(lastException);
    }

    // 优化代理设置，增加代理有效性检查 i=0 需要代理 其他不需要代理
    private OkHttpClient buildClient(boolean useProxy) {
        OkHttpClient.Builder clientBuilder = (ignoreCertificates ? getInsecureClient() : defaultClient).newBuilder()
                .connectTimeout(timeoutMillis-100, TimeUnit.MILLISECONDS)
                .readTimeout((timeoutMillis+100), TimeUnit.MILLISECONDS)
                .writeTimeout(timeoutMillis-100, TimeUnit.MILLISECONDS);
        /*if(i==1){

        }else*/
        // 动态设置代理
        int limit = 1;
        //http://121.62.30.160:2025/api/user/1000/android/5.3.3/vip
        //https://uyz.mmlwo.cn/api/user/1000/android/1.01087/heartbeat


        if (proxySupplier != null&&useProxy) {
            HttpHost proxy = proxySupplier.get();
            if (proxy != null && isValidProxy(proxy)) {
                clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy.getHostName(), proxy.getPort())));
            }
        }

        return clientBuilder.build();
    }

    // 获取忽略证书验证的客户端
    private OkHttpClient getInsecureClient() {
        if (insecureClient == null) {
            synchronized (OkHttpUtil.class) {
                if (insecureClient == null) {
                    try {
                        // 创建信任所有证书的 TrustManager
                        TrustManager[] trustAllCerts = new TrustManager[]{
                            new X509TrustManager() {
                                @Override
                                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                                }

                                @Override
                                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                                }

                                @Override
                                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                    return new java.security.cert.X509Certificate[]{};
                                }
                            }
                        };

                        // 创建 SSLContext 并使用信任所有证书的 TrustManager
                        SSLContext sslContext = SSLContext.getInstance("SSL");
                        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

                        // 创建 SSLSocketFactory 并使用 SSLContext
                        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

                        insecureClient = new OkHttpClient.Builder()
                                .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
                                .hostnameVerifier((hostname, session) -> true)
                                .build();
                    } catch (Exception e) {
                        throw new RuntimeException("Failed to create insecure OkHttpClient", e);
                    }
                }
            }
        }
        return insecureClient;
    }

    // 检查代理有效性
    private boolean isValidProxy(HttpHost proxy) {
        return proxy != null && proxy.getHostName() != null && proxy.getPort() > 0;
    }


   /* public static void main(String[] args) {
        Integer a = 8;
        try{
            testExc(a);
        }catch (Exception e){
            log.error("main error",e);
        }

    }

    private static Integer testExc(Integer a) {
        Integer b = null;
        try{
            a = a +1;
            return a+b;

        }catch (Exception e){
            log.error("testExc error",e);
        }finally {
            log.info("finally");
        }
        return 0;
    }*/
}
